package wellplatescanner;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Vector;

import javax.imageio.ImageIO;

import SK.gnome.morena.Morena;
import SK.gnome.morena.MorenaException;
import SK.gnome.morena.MorenaImage;
import SK.gnome.twain.TwainException;
import SK.gnome.twain.TwainManager;
import SK.gnome.twain.TwainSource;



public class ScannerDevice {
	
	public static interface IDeviceChangedListener {
		void scanCompleted();
		void connected();
	}
	
	private TwainSource source;
	private Thread thread;
	private Vector messageQueue = new Vector();
	ScannerCapabilities capabilities;
	ScannerSettings settings;
	IDeviceChangedListener listener;
	boolean isScanning = false;
	
	private static final int MSG_CONNECT = 1;
	private static final int MSG_CLOSE = 2;
	private static final int MSG_SCAN = 3;
	
	
	public static class ScannerSettings {
		public double resolution;
		public boolean lampState;
		public int lightPath;
		public int lightSource;
		public double gamma;
		public double brightness;
		public double contrast;
		public double exposureTime;
	}
	
	public static class ScannerCapabilities {
		boolean[] supportedLampState;
		int[] supportedLightPath;
		int[] supportedLightSource;
		double[] supportedBrightness;
		double[] supportedContrast;
		double[] supportedExposureTime;
	}
	
	public synchronized void setChangeListener(IDeviceChangedListener listener) {
		this.listener = listener;
	}
	
	public ScannerDevice() {
		thread = new Thread(new Runnable() {
			@Override
			public void run() {
				while(true) {
					if(messageQueue.size() > 0) {
						int msg = (Integer)messageQueue.firstElement();
						messageQueue.remove(0);
						switch(msg) {
						case MSG_CONNECT:
					    	try {
					    		
					    		// TODO: scanner worker thread ? (this takes some time)
					    		
					    		TwainSource newSource = TwainManager.getDefaultSource();

								// Set default properties
						    	//source.setAutoScan(true);
						    	newSource.setVisible(false);
						        newSource.setColorMode();   
								
						        // Get capabilities
								capabilities = new ScannerCapabilities();
								capabilities.supportedLampState = newSource.getSupportedLampState();
								capabilities.supportedLightPath = newSource.getSupportedLightPath();
								capabilities.supportedLightSource = newSource.getSupportedLightSource();
								capabilities.supportedBrightness = newSource.getSupportedBrightness();
								capabilities.supportedContrast = newSource.getSupportedContrast();
								capabilities.supportedExposureTime = newSource.getSupportedExposureTime();

						        // Get settings
								settings = new ScannerSettings();
								settings.resolution = newSource.getResolution();
								settings.lampState = newSource.getLampState();
								settings.lightPath = newSource.getLightPath();
								settings.lightSource = newSource.getLightSource();
								settings.gamma = newSource.getGamma();
								settings.brightness = newSource.getBrightness();
								settings.contrast = newSource.getContrast();
								settings.exposureTime = newSource.getExposureTime();

								
								Log.println("Scanner: connected to " + newSource);
								
								source = newSource;
								
								if(listener != null) {
									listener.connected();
								}
								
							} catch (TwainException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
							break;
						case MSG_SCAN:
							
							String projectFolder = (String)messageQueue.firstElement();
							messageQueue.remove(0);
							ScannerSettings settings = (ScannerSettings)messageQueue.firstElement();
							messageQueue.remove(0);
							
						    try {

						    	
						    	source.setResolution(settings.resolution);
						    	source.setLightPath(settings.lightPath);
						    	source.setLightSource(settings.lightSource);
						    	source.setLampState(settings.lampState);
						    	source.setGamma(settings.gamma);
						    	source.setBrightness(settings.brightness);
						    	source.setContrast(settings.contrast);
						    	source.setExposureTime(settings.exposureTime);
						    	
						    	System.err.println("Image resolution is " +source.getResolution());
						    	
//							        source.setsetAutoBright(boolean value)
//							        setAutomaticDeskew(boolean value)
//							        setAutomaticRotate(boolean value)
//							        
//							        int getBitDepth()
//							        int[] getSupportedBitDepth()
//							        int getDefaultBitDepth()

					//




							        //turn off light 
							        
							        
							    Log.println("Scanner: Starting scan ... ");
					       
							    MorenaImage morenaImage=new MorenaImage(source);

							    System.err.println("Size of acquired image is "
							      	+morenaImage.getWidth()+" x "
							      	+morenaImage.getHeight()+" x "
							      	+morenaImage.getPixelSize());

							    Image image=Toolkit.getDefaultToolkit().createImage(morenaImage); 
								BufferedImage bimg=new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);
								bimg.createGraphics().drawImage(image, 0, 0, null);
								try {
								   	SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HH_mm");
								   	Calendar cal = Calendar.getInstance();
									String time = sdf.format(cal.getTime());
									String fileName = "Sample_" + time + ".jpg";
									ImageIO.write(bimg,"jpg",new File(projectFolder + "/" + fileName));
									Log.println("Scan complete. Saved as " + fileName);

									if(listener != null) {
										listener.scanCompleted();
									}
								
								} catch (IOException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}
								    
						    } catch (TwainException e1) {
								// TODO Auto-generated catch block
								e1.printStackTrace();
							}
						    
						    isScanning = false;
						    
							break;
						}
					}
				}
			}
		});
		thread.start();
	}
	
	public void connect() {
		
		if(source != null) {
			return;
		}
		
		messageQueue.add(MSG_CONNECT);
	}
	
	public synchronized void close() {
		Log.println("Scanner: Closing connection");
		try {
			Morena.close();
		} catch (MorenaException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		source = null;
		capabilities = null;
		isScanning = false;
	}
	
	public synchronized boolean isScanning() {
		return isScanning;
	}
	
	
	public synchronized boolean isConnected() {
		return source != null;
	}
	
	public synchronized ScannerCapabilities getCapabilities() {
		if(source == null) {
			Log.println("Scanner: Failed to get capabilities. Not connected to scanner");
			return null;
		}
		
		return capabilities;
	}
	
	public synchronized ScannerSettings getSettings() {
		if(source == null) {
			Log.println("Scanner: Failed to get settings. Not connected to scanner");
			return null;
		}
		
		return settings;
	}
	
	public void aquire(String projectFolder, ScannerSettings settings) {
		
		if(source == null) {
			Log.println("Scanner: Failed to aquire image. Not connected to scanner");
			return;
		}
		isScanning = true;

		messageQueue.add(MSG_SCAN);
		messageQueue.add(projectFolder);
		messageQueue.add(settings);
    }
}
